package net.luohuasheng.bee.proxy.core.enums;

import java.io.InputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author luohuasheng
 * @date 2020/4/18 21:35
 */
public enum DataType {
    BOOLEAN(DataCategory.BOOLEAN, 1, false, false, Boolean.class, true),
    INTEGER_SHORT(DataCategory.INTEGER, 4, false, false, Short.class, true),
    INTEGER_SHORT_UNSIGNED(DataCategory.INTEGER, 3, true, false, Short.class, false),
    INTEGER(DataCategory.INTEGER, 10, false, false, Integer.class, true),
    INTEGER_UNSIGNED(DataCategory.INTEGER, 9, true, false, Integer.class, false),
    INTEGER_LONG(DataCategory.INTEGER, 20, false, false, Long.class, true),
    INTEGER_LONG_UNSIGNED(DataCategory.INTEGER, 19, true, false, Long.class, false),
    INTEGER_BIGINT(DataCategory.INTEGER, 255, false, false, BigInteger.class, true),
    INTEGER_BIGINT_UNSIGNED(DataCategory.INTEGER, 254, true, false, BigInteger.class, false),
    DECIMAL(DataCategory.DECIMAL, 10, false, true, Float.class, true),
    DECIMAL_UNSIGNED(DataCategory.DECIMAL, 9, true, true, Float.class, false),
    DECIMAL_LONG(DataCategory.DECIMAL, 20, false, true, Double.class, true),
    DECIMAL_LONG_UNSIGNED(DataCategory.DECIMAL, 19, true, true, Double.class, false),
    DECIMAL_BIGINT(DataCategory.DECIMAL, 20, false, true, BigDecimal.class, true),
    DECIMAL_BIGINT_UNSIGNED(DataCategory.DECIMAL, 19, true, true, BigDecimal.class, false),
    CHARACTER(DataCategory.CHARACTER, 1, false, false, Character.class, true),
    CHARACTER_SMALL_STRING(DataCategory.CHARACTER, 255, false, false, String.class, true),
    CHARACTER_STRING(DataCategory.CHARACTER, 10000, false, false, String.class, false),
    CHARACTER_CLOB(DataCategory.CHARACTER, Integer.MAX_VALUE, false, false, String.class, false),
    CHARACTER_BYTE(DataCategory.CHARACTER, 1, false, false, Byte.class, true),
    DATE(DataCategory.DATE, 0, false, false, java.sql.Date.class, true),
    TIME(DataCategory.TIME, 0, false, false, java.sql.Time.class, true),
    DATE_TIME(DataCategory.DATE_TIME, 0, false, false, Date.class, true),
    BLOB(DataCategory.INPUT_STREAM, Integer.MAX_VALUE, false, false, InputStream.class, true),
    BLOB_BYTES(DataCategory.INPUT_STREAM, Integer.MAX_VALUE, false, false, Byte[].class, true),

    ;
    /**
     * 转换数据类型
     *
     * @see DataCategory
     */
    private final int dataCategory;
    /**
     * 最大长度
     */
    private final int maxSize;
    /**
     * 是否含有精度
     */
    private final boolean isUnsigned;

    /**
     * 是否含有精度
     */
    private final boolean hasDigits;

    /**
     * 对应java类型
     */
    private final Class<?> javaType;
    /**
     * 是否默认类型
     */
    private final boolean isDefault;


    DataType(int dataCategory, int maxSize, boolean isUnsigned, boolean hasDigits, Class<?> javaType, boolean isDefault) {
        if (javaType.isPrimitive()) {
            javaType = Objects.requireNonNull(PrimitiveType.getType(javaType)).getClassZ();
        }
        this.isDefault = isDefault;
        this.dataCategory = dataCategory;
        this.maxSize = maxSize;
        this.isUnsigned = isUnsigned;
        this.hasDigits = hasDigits;
        this.javaType = javaType;
    }

    public static List<DataType> getTypeByJavaType(Class<?> javaType, boolean isUnsigned) {
        return Arrays.stream(values())
                .filter(columnType -> columnType.javaType.equals(javaType) && (isUnsigned == columnType.name().contains("UNSIGNED")))
                .collect(Collectors.toList());
    }

    public static DataType getDefaultType(Class<?> javaType) {
        return Arrays.stream(values())
                .filter(columnType -> columnType.javaType.equals(javaType) && (columnType.isDefault))
                .findFirst().orElse(BLOB);
    }

    public static List<DataType> getTypeByDataCategory(int dataCategory, boolean isUnsigned) {
        return Arrays.stream(values())
                .filter(columnType -> columnType.dataCategory == dataCategory && (isUnsigned == columnType.name().contains("UNSIGNED")))
                .collect(Collectors.toList());
    }

    public int getDataCategory() {
        return dataCategory;
    }

    public int getMaxSize() {
        return maxSize;
    }

    public boolean isUnsigned() {
        return isUnsigned;
    }

    public boolean isHasDigits() {
        return hasDigits;
    }

    public Class<?> getJavaType() {
        return javaType;
    }
}
